<?php

namespace app\common\model;

use app\common\controller\Queue;
use think\Db;
use think\Exception;
use think\Model;
use traits\model\SoftDelete;

class Order extends Model
{

    use SoftDelete;

    

    // 表名
    protected $name = 'order';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    protected $deleteTime = 'delete_time';

    // 追加属性
    protected $append = [
        'pay_time_text',
        'shipping_time_text',
        'sign_time_text',
	    'status_text',
	    'order_type_text',
	    'pay_status_text',
	    'shipping_status_text',
	    'close_reason'
    ];
    
	const STATUS_WAIT = 0;
	const STATUS_SHIPPING = 1;
	const STATUS_SIGN = 2;
	const STATUS_SUCCESS = 3;
	const STATUS_CLOSE = -1;
	
	public static $statusList = [
		self::STATUS_SHIPPING => '待发货',
		self::STATUS_WAIT => '待付款',
		self::STATUS_SIGN => '待签收',
		self::STATUS_SUCCESS => '已完成',
		self::STATUS_CLOSE => '已关闭'
	];
    
	public function getStatusTextAttr($value, $data) {
		$value = $value ? : $data['status'];
		$list = self::$statusList;
		return $list[$value] ?? '';
	}

	const TYPE_NORMAL = 1;
	const TYPE_TRY = 2;
	
	public static $typeList = [
		self::TYPE_NORMAL => '普通订单',
		self::TYPE_TRY => '试用订单'
	];
	
	public function getOrderTypeTextAttr($value, $data) {
		$value = $value ? : $data['order_type'];
		$list = self::$typeList;
		return $list[$value] ?? '';
	}
	
	const PAY_STATUS_WAIT = 0;
	const PAY_STATUS_Y = 1;
	const PAY_STATUS_REFUND = 2;
	
	public static $payStatusList = [
		self::PAY_STATUS_Y => '已支付',
		self::PAY_STATUS_WAIT => '待支付',
		self::PAY_STATUS_REFUND => '已退款'
	];
	
	public function getPayStatusTextAttr($value, $data) {
		$value = $value ? : $data['pay_status'];
		$list = self::$payStatusList;
		return $list[$value] ?? '';
	}
	
	const SHIPPING_STATUS_WAIT = 0;
	const SHIPPING_STATUS_SIGN = 1;
	const SHIPPING_STATUS_REFUND = 2;
	
	public static $shippingStatusList = [
		self::SHIPPING_STATUS_SIGN => '已签收',
		self::SHIPPING_STATUS_REFUND => '已退货',
		self::SHIPPING_STATUS_WAIT => '已发货'
	];
	
	public function getShippingStatusTextAttr($value, $data) {
		$value = $value ? : $data['shipping_status'];
		$list = self::$shippingStatusList;
		return $list[$value] ?? '';
	}
	
	const CANCEL_REASON_TIME = 1;
	const CANCEL_REASON_USER = 2;
	
	public static $cancelReasonList = [
		self::CANCEL_REASON_TIME => '超时取消',
		self::CANCEL_REASON_USER => '用户取消'
	];
	
	public function getCancelReasonTextAttr($value, $data) {
		$value = $value ? : $data['canceL_reason'];
		$list = self::$cancelReasonList;
		return $list[$value] ?? '';
	}
	
	
    public function getPayTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['pay_time']) ? $data['pay_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getShippingTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['shipping_time']) ? $data['shipping_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getSignTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['sign_time']) ? $data['sign_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }

    protected function setPayTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setShippingTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setSignTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }
    
    public function user() {
		return $this->belongsTo('user', 'user_id', 'id', '', 'left')->setEagerlyType(0);
    }
	
	/**
	 * 获取订单列表
	 * @param $userId
	 * @param int $page
	 * @param string $status
	 * @return array
	 * @throws \think\Exception
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 */
    public function getOrderList($userId, $page = 1, $status = '') {
		$where = [
			'user_id' => $userId,
			'is_delete' => 0
		];
		
		strlen($status) > 0 && $where['status'] = $status;
		
		$count = $this->where($where)->count();
		$list = $this->where($where)
			->order(['update_time' => 'desc'])
			->page($page)
			->select();
		
		if($list) {
			foreach ($list as &$item) {
					$goods = Db::name('orderGoods')
					->where(['order_id' => $item['id']])
					->select();
					foreach ($goods as &$good) {
						$good['goods_info'] = json_decode($good['goods_info'], true);
					}
				
				$item['goods']  = $goods;
			}
		}
		
		return [
			'total' => $count,
			'list' => $list
		];
    }
    
    
    public function createOrder($userId, $data, $type = 1) {
        if($data['type'] == 'goods') {
            //单商品购买
	        $goodsList = Db::name('goods')->alias('g')
		        ->join('goodsSpec s', 'g.id = s.goods_id and s.id = \''.$data['goods_spec_id'].'\'', 'left')
		        ->where(['g.id' => $data['goods_id']])
		        ->field('g.id as goods_id, g.status, s.id as goods_spec_id, '.$data['number'].' as number, g.price, g.number_store, g.name, g.image, g.point_price, g.goods_type, g.shipping_price, s.price as spec_price, s.store_count as spec_store, s.image as spec_image, s.name as spec_name, \''.$data['recommend_user_id'].'\' as recommend_user_id')
		        ->select();
        } else {
        	//购物车购买
	        $ids = $data['cart_ids'];
	        $goodsList = Db::name('cart')->alias('c')
		        ->join('goods g', 'c.goods_id = g.id', 'left')
		        ->join('goodsSpec s', 'c.goods_spec_id = s.id', 'left')
		        ->where(['c.user_id' => $userId, 'c.id' => ['in', $ids]])
		        ->field('c.goods_id, c.goods_spec_id, c.recommend_user_id, g.status, c.number, g.price, g.number_store, g.name, g.image, g.point_price, g.goods_type, g.shipping_price, s.price as spec_price, s.store_count as spec_store, s.image as spec_image, s.name as spec_name')
		        ->select();
        }
        
        if(!$goodsList) {
        	$this->error = '请选择要购买的商品';
        	return false;
        }
        
        $goodsAmount = 0;
        $offerAmount = 0;
        $couponAmount = 0;
        $pointAmount = 0;
        $number = 0;
        $shippingAmount = 0;
        $orderType = self::TYPE_NORMAL;
        
        foreach($goodsList as $item) {
        	if($item['status'] != Goods::STATUS_SALE) {
        		$this->error = $item['name'].'已下架';
        		return false;
	        } else {
        		$price = $item['spec_price'] ? : $item['price'];
        		$store = $item['spec_store'] ? : $item['number_store'];
        		if($item['number'] > $store) {
        			$this->error = '库存不足';
        			return false;
		        }
        		$goodsAmount += $item['number'] * $price;
        		$number += $item['number'];
        		$pointAmount += $item['point_price'];
		        $shippingAmount += $item['shipping_price'];
	        }
        	
        	if($item['goods_type'] == Goods::TYPE_TRY) {
        		$orderType = self::TYPE_TRY;
	        }
        }
        
        //试用商品，查看是否有购买过，第一次不用积分
        if($orderType == self::TYPE_TRY) {
        	$tryOrder = Db::name('order')
		        ->where(['user_id' => $userId, 'order_type' => self::TYPE_TRY, 'status' => ['neq', self::STATUS_CLOSE]])
		        ->find();
        	
        	if(!$tryOrder) {
        	    $pointAmount = 0;
	        }
        }
        
        
	    $amount = $goodsAmount - $offerAmount - $couponAmount+$shippingAmount;
        
        if($type == 1) {
        	return [
        	    'amount' => $amount,
		        'number' => $number,
		        'goods' => $goodsList,
		        'point_amount' => $pointAmount,
		        'order_type' => $orderType,
		        'shipping_amount' => $shippingAmount
	        ];
        }
        
        if(!$data['address_id']) {
        	$this->error = '请选择收货地址';
        	return false;
        }
        
        if($pointAmount > 0) {
        	$user = \app\admin\model\User::get($userId);
        	if($user['score'] < $pointAmount) {
        		$this->error = '积分不足,当前积分【'.$user['score'].'】,可签到获取积分!';
        		return false;
	        }
        }
        
        
        $this->startTrans();
        try {
        	$res = $this->isUpdate(false)
		        ->save([
		        	'user_id' => $userId,
			        'order_no' => time().mt_rand(10000, 99999),
			        'goods_amount' => $goodsAmount,
			        'offer_amount' => $offerAmount,
			        'coupon_amount' => $couponAmount,
			        'amount' => $amount,
			        'number' => $number,
			        'remark' => $data['remark'] ??'',
			        'order_type' => $orderType,
			        'point_amount' => $pointAmount,
			        'shipping_amount' => $shippingAmount,
			        'status' => $amount > 0 ? self::STATUS_WAIT : self::STATUS_SHIPPING
		        ]);
        	
        	if(!$res) {
        		throw new Exception('添加订单出错');
	        }
        	
        	$orderId = $this->getLastInsID();
        	
        	//减积分
	        if($pointAmount > 0) {
	        	$userRes = Db::name('user')->where(['id' => $userId])->setDec('score', $pointAmount);
	        	if(!$userRes) {
	        		throw new Exception('扣除积分出错');
		        }
	        	
	        	$fundModel = new Funds();
	        	$fundRes = $fundModel->addRecord($userId, $pointAmount, $user['score'], $fundModel::ACCOUNT_TYPE_INTEGRAL, $fundModel::OPE_TYPE_LESS, $fundModel::TYPE_PAY_ORDER, $orderId);
	        	if(!$fundRes) {
	        		throw new Exception('记录积分记录出错');
		        }
	        }
        	
        	$goodsData = [];
        	foreach ($goodsList as $item) {
        		$goods = Db::name('goods')->alias('g')
			        ->join('goodsSpec s', 'g.id = s.goods_id and s.id = \''.$item['goods_spec_id'].'\'', 'left')
			        ->where(['g.id' => $item['goods_id']])
			        ->field('g.*, s.id as spec_id, s.price as spec_price, s.store_count as spec_store, s.image as spec_image, s.name as spec_name')
			        ->find();
        		
        		if($item['goods_spec_id']) {
        		    $storeRes = Db::name('goodsSpec')->where(['id' => $item['goods_spec_id']])->setDec('store_count', $item['number']);
		        } else {
        			$storeRes = Db::name('goods')->where(['id' => $item['goods_id']])->setDec('number_store', $item['number']);
		        }
        		
        		if(!$storeRes) {
        			throw new Exception('减少商品库存出错');
		        }
        		
        		$rebateInfo = Db::name('goodsRebate')->where(['goods_id' => $item['goods_id']])->find();
        		$goodsData[] = [
        		    'order_id' => $orderId,
			        'goods_id' => $item['goods_id'],
			        'number' => $item['number'],
			        'amount' => ($item['spec_price'] ? : $item['price']) * $item['number'],
			        'commission' => $goods['commission'] * $item['number'],
			        'spec_name' => $item['spec_name'],
			        'recommend_user_id' => $item['recommend_user_id'] ? : 0,
			        'goods_info' => json_encode($goods),
			        'create_time' => time(),
			        'update_time' => time(),
			        'rebate_info' => json_encode($rebateInfo),
		        ];
	        }
        	
        	$goodsRes = Db::name('orderGoods')->insertAll($goodsData);
        	if(!$goodsRes) {
        		throw new Exception('添加订单商品出错');
	        }
        	
        	$address = Db::name('address')->find($data['address_id']);
        	$address['order_id'] = $orderId;
        	$addressModel = new OrderAddress();
        	unset($address['id']);
        	$addressRes = $addressModel->allowField(true)->isUpdate(false)->save($address);
        	if(!$addressRes) {
        		throw new Exception('添加收货地址出错');
	        }
        	
        	$this->commit();
        	return [
        		'id' => $orderId,
		        'amount' => $amount,
		        'order_type' => $orderType
	        ];
        } catch (Exception $e) {
        	$this->error = $e->getMessage();
        	$this->rollback();
        	return false;
        }
    }
	
	
	/**
	 * 支付成功
	 * @param $id
	 * @return bool
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 * @throws \think\exception\PDOException
	 */
    public function paySuccess($id) {
    	$order = $this->find($id);
    	if(!$order) {
    		$this->error = '订单不存在';
    		return false;
	    }
    	
//    	if($order['status'] != self::STATUS_WAIT) {
//    		$this->error = '非待支付订单';
//    		return false;
//	    }
    	
    	$this->startTrans();
    	try {
    		//更改订单状态
		    $res = $this->save(
		    	[
		    		'status' => self::STATUS_SHIPPING,
				    'pay_status' => self::PAY_STATUS_Y,
				    'pay_time' => time()
			    ],
			    ['id' => $id]);
		    
		    if(!$res) {
		    	throw new Exception('更改订单状态出错');
		    }
		
		    Queue::addTask('orderPaySuccess', ['id' => $id]);
		    
    		
    		$this->commit();
    		return true;
	    } catch (Exception $e) {
    		$this->rollback();
    		$this->error = $e->getMessage();
    		return false;
	    }
    }
	
	/**
	 * 签收订单
	 * @param $id
	 * @param string $userId
	 * @return bool
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 * @throws \think\exception\PDOException
	 */
    public function sign($id, $userId = '') {
	
    	$where['id'] = $id;
	    $userId && $where['user_id'] = $userId;
	    $order = $this->where($where)->find();
	    
	    if(!$order) {
	    	$this->error = '订单不存在';
	    	return false;
	    }
	    if ($order['status'] != self::STATUS_SIGN) {
		    $this->error = '非待签收订单';
		    return false;
	    }
	
	    $this->startTrans();
	    try {
		    $res = $this->save([
			    'status' => self::STATUS_SUCCESS,
			    'sign_time' => time(),
			    'shipping_status' => self::SHIPPING_STATUS_SIGN
		    ], ['id' => $id]);
		    
		    if(!$res) {
		    	throw new Exception("更改订单状态出错");
		    }
		    
		    $model = new Commission();
		    $commissionRes = $model->rebate($id);
		    if(!$commissionRes) {
		    	throw new Exception('添加佣金出错'.$model->getError());
		    }
		    
		    $this->commit();
		    return true;
	    } catch (Exception $e) {
	    	$this->error = $e->getMessage();
	    	$this->rollback();
	    	return false;
	    }
	    
    }
	
	
	/**
	 * 取消订单
	 * @param $id
	 * @param $reason
	 * @param string $userId
	 * @return bool
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 * @throws \think\exception\PDOException
	 */
    public function cancel($id, $reason, $userId = '') {
	    $where['id'] = $id;
	    $userId && $where['user_id'] = $userId;
	    $order = $this->where($where)->find();
	
	    if(!$order) {
		    $this->error = '订单不存在';
		    return false;
	    }
	    if ($order['status'] != self::STATUS_WAIT) {
		    $this->error = '订单不可取消';
		    return false;
	    }
	
	    $this->startTrans();
	    try {
		    $res = $this->save([
			    'status' => self::STATUS_CLOSE,
			    'close_reason' => $reason
		    ], ['id' => $id]);
		
		    if(!$res) {
			    throw new Exception("更改订单状态出错");
		    }
		
		    //添加商品库存
		    $goods = Db::name('orderGoods')
			    ->where(['order_id' => $id])
			    ->select('id, goods_id, number, goods_spec_id')
			    ->select();
		    foreach ($goods as $good) {
		    	if($good['goods_spec_id']) {
		    		$numRes = Db::name('goodsSpec')
					    ->where(['id' => $good['goods_spec_id']])
					    ->setInc('store_count', $good['number']);
			    } else {
				    $numRes = Db::name('goods')
					    ->where(['id' => $good['goods_id']])
					    ->setInc('number_store', $good['number']);
			    }
			    if($numRes === false) {
				    throw new Exception('添加商品库存出错');
			    }
		    }
		
		    $this->commit();
		    return true;
	    } catch (Exception $e) {
		    $this->error = $e->getMessage();
		    $this->rollback();
		    return false;
	    }
    }
	
	/**
	 * 积分试用订单支付
	 * @param $orderId
	 * @return bool
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 * @throws \think\exception\PDOException
	 */
    public function pointPay($orderId) {
    	$order = $this->find($orderId);
	    if(!$order) {
		    $this->error = '订单不存在';
		    return false;
	    }
    	
    	if($order['status'] != self::STATUS_WAIT) {
    		$this->error = '非待支付订单';
    		return false;
	    }
    	
    	$user = \app\admin\model\User::get($order['user_id']);
    	if($user['score'] < $order['point_amount']) {
    		$this->error = '积分不足';
    		return false;
	    }
    	
    	$this->startTrans();
    	try {
    		
    		//更改订单状态
		    $res = $this->save(
			    [
				    'status' => self::STATUS_SHIPPING,
				    'pay_status' => self::PAY_STATUS_Y,
				    'pay_time' => time()
			    ],
			    ['id' => $orderId]);
		
		    if(!$res) {
			    throw new Exception('更改订单状态出错');
		    }
		    
		    //扣除积分
		    $userRes = Db::name('user')
			    ->where(['id' => $order['user_id']])
			    ->setDec('score', $order['point_amount']);
		    if(!$userRes) {
		    	throw new Exception('扣除积分出错');
		    }
		    
		    //记录流水
		    $fundModel = new Funds();
		    $fundsRes = $fundModel->addRecord($order['user_id'], $order['point_amount'], $user['score'], $fundModel::ACCOUNT_TYPE_INTEGRAL, $fundModel::OPE_TYPE_LESS, $fundModel::TYPE_PAY_ORDER, $orderId);
		    if(!$fundsRes) {
		    	throw new Exception('添加积分记录出错');
		    }
		    
    		$this->commit();
    		return true;
	    } catch (Exception $e) {
    		$this->rollback();
    		$this->error = $e->getMessage();
    		return false;
	    }
    }
}
